

#include<iostream>
#include<string>
#include<fstream>
#include<algorithm>
#include<iterator>
#include<functional>
#include<ctime>
#include<iomanip>
#include<unordered_map>
#include<thread>
#include<chrono>
#include<cstdlib>
#include<cstring>
#include<tuple>
#include<vector>
#include<numeric>
#include<bitset>
#include<string_view>
#include<new>
#include<queue>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<curl/curl.h>
#include<set>




struct curlStruct
{
	const int bufLen{ 128 };
	char* curlBuf = new (std::nothrow) char[bufLen];
	int curlPos{ 0 };
};


//curl回调函数使用的变量
static char* source;
static curlStruct* thisCurlStruct;
static int sizeNmemb;


//curl回调函数，将请求返回的数据保存进curlStruct.curlBuf里面
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
	source = reinterpret_cast<char*>(contents);
	if (userp)
	{
		thisCurlStruct = reinterpret_cast<struct curlStruct*>(userp);
		sizeNmemb = size * nmemb;
		if (sizeNmemb < std::distance(thisCurlStruct->curlBuf + thisCurlStruct->curlPos, thisCurlStruct->curlBuf + thisCurlStruct->bufLen))
		{
			std::copy(source, source + sizeNmemb, thisCurlStruct->curlBuf + thisCurlStruct->curlPos);
			thisCurlStruct->curlPos += sizeNmemb;
			*(thisCurlStruct->curlBuf + thisCurlStruct->curlPos) = '\0';
		}
	}

	return size * nmemb;
}


int main()
{

	/////////////////////////////////////////变量区


	//curl相关变量
	CURL* curl;
	CURLcode res;
	curl_slist* headers{};
	curlStruct curlPack;
	if (!curlPack.curlBuf)
		return -101;





	//////////////////发送邮件变量
	const std::string
		ColaKeyHeader{ R"({"ColaKey":")" },
		tomailHeader{ R"(", "tomail":")" },
		fromTitleHeader{ R"(","fromTitle":")" },
		subjectHeader{ R"(","subject":")" },
		smtpCodeHeader{ R"(","smtpCode":")" },
		smtpEmailHeader{ R"(","smtpEmail":")" },
		smtpCodeTypeHeader{ R"(","smtpCodeType":")" },
		isTextContentHeader{ R"(","isTextContent":)" },
		contentHeader{ R"(,"content":")" },
		emailBack{ R"("})" },
		banIP{ "banIP:" },
		banType{ "banType:" },
		loginIP{ "loginIP:" },
		loginType{ "loginType:" }
	;



	//////////////////发送邮件各配置项变量
	//参考网址:https://blog.csdn.net/qq_48896417/article/details/130298611
	//官网地址:http(s): //luckycola.com.cn/
	//下列参数可以查看官网api介绍，自己设置好填上去就行
	//content内容实时拼接
	const std::string
		ColaKey{  },
		tomail{  },
		fromTitle{  },
		subject{  },
		smtpCode{  },
		smtpEmail{  },
		smtpCodeType{ },
		isTextContent{  };







	//发送邮件用的缓冲区以及指针
	const int sendBufLen{ 50000 };
	char* sendBuf = new char[sendBufLen];
	char* sendPos{ sendBuf };
	//从sendBuf到mixSendPos之间的字符是固定不变的，每次发送完消息后复位到mixSendPos即可
	const char* mixSendPos{ sendBuf + ColaKeyHeader.size() + tomailHeader.size() + fromTitleHeader.size() + subjectHeader.size()
	+ smtpCodeHeader.size() + smtpEmailHeader.size() + smtpCodeTypeHeader.size() + isTextContentHeader.size()
	+ contentHeader.size() + ColaKey.size() + tomail.size() + fromTitle.size() + subject.size()
	+ smtpCode.size() + smtpEmail.size() + smtpCodeType.size() + isTextContent.size() };



	//记录封禁IP信息的文件所用的变量
	//banBufLen是根据到2099年最后一天的std::time_t值加上IPV6的最长长度再加上两位的封禁类型再加上一个\n的和，
	// 乘以600得到的值再加100的冗余长度计算出来的
	// 当有IP被解禁时，根据file_pos在文件中覆盖file_len长度的内容，实现O(1)清除封禁IP的信息
	//banBufBegin指向每次准备写入字符串的起始位置，banBufPos指向写入后的实际位置
	//unsealNum为已经解禁过IP的累积次数
	//maxUnsealNum的意思为达到这个数的时候，执行重建banFile的操作，节省硬盘空间
	//unsealCheckTimeMax为执行检查是否达到maxUnsealNum的sleepTime周期，1440为24小时  1440*60，单位次
	const int banBufLen{ 32400 };
	char* banBuf = new (std::nothrow) char[banBufLen];
	if (!banBuf)
		return -101;
	char* banBufBegin{ banBuf }, *banBufPos{ banBuf };
	unsigned int beginPos{};
	unsigned int unsealNum{};
	const unsigned int maxUnsealNum{ 10000 };
	unsigned int unsealCheckTime{ };
	const unsigned int unsealCheckTimeMax{ 1440 };
	const char space[1]{ ' ' };



	//用于操作super_bit的变量	
	std::bitset<8>bit;


	//保存时间戳字符串的变量
	const unsigned int timeBufLen{ 10 };
	unsigned char timeBuf[timeBufLen];


	//检测某IP是否属于IPV6 CIDR的变量
	struct in6_addr ipv6;
	struct in6_addr net;
	int prefix;
	char* ptr = nullptr;
	uint8_t mask[16];



	//检测某IP是否属于IPV4 CIDR的变量
	char* pos;
	uint32_t val;
	uint32_t msk;
	uint32_t offset;
	uint32_t tar;

	//装载system命令的buf
	const int commandBufLen{ 5000 };
	char* commandBuf = new (std::nothrow) char[commandBufLen];
	if (!commandBuf)
		return -101;
	char* commandPos;
	std::vector<std::string>::const_iterator ignoreIpBegin;


	const int ipv4MixLen{ 6 }, ipv6MixLen{ 2 }, ipv6MaxLen{ 43 }, ipv4NumMaxLen{ 3 }, ipv6NumMaxLen{ 4 };
	std::vector<std::string>::const_iterator vecBegin, vecEnd;
	std::string::const_iterator checkBegin, checkEnd;
	int j;
	const float f2{ 10.0f };
	float f3;
	int sum;
	int thisLoginType;                          //登录类型
	std::set<std::string>loginIpSet;


	//年月日时分秒在时间字符串内的位置
	const int
		year1{ 0 }, year2{ 1 }, year3{ 2 }, year4{ 3 },
		month1{ 5 }, month2{ 6 },
		day1{ 8 }, day2{ 9 },
		hour1{ 11 }, hour2{ 12 },
		minute1{ 14 }, minute2{ 15 },
		second1{ 17 }, second2{ 18 }
	;

	const std::string strFail{ "Failed" }, strAccept{ "Accepted" }, strFrom{ "from" }, strA{ "-A INPUT -s" },
		strchmod{ "chmod 666 " }, strIptablesSave{ "service iptables save" }, strIptablesRestart{ "service iptables restart" },
		strxui{ "x-ui" }, strWrong{ "wrong" }, strFindIP{ "IP:" }, strAccessDen{ "Access denied" }, strErrorPass{ "Error password" },
		straddr{ "addr=" }, strAccess{ "Access" }, strSuccess{ "success" }, strFailed{ "failed" },
		strIptables_I{ "iptables -I INPUT -s " }, strDrop{ " -j DROP" }, strIptables_F{ "iptables -F" },
		strIptables_D{ "iptables -D INPUT -s " },
		strIp6tables_I{ "ip6tables -I INPUT -s " }, strIp6tables_F{ "ip6tables -F" },
		strIp6tables_D{ "ip6tables -D INPUT -s " },
		strIp6tablesSave{ "service ip6tables save" }, strIp6tablesRestart{ "service ip6tables restart" },

		//乌班图ufw 默认allow规则，可以根据需要进行修改  3306为mysql端口  6379为redis端口
		ufwAllow{ "ufw allow ssh;ufw allow http;ufw allow 443/tcp;ufw allow 3306/tcp;ufw allow 6379/tcp;" },
		ufwDisAllow{ "ufw delete allow ssh;ufw delete allow http;ufw delete allow 443/tcp;ufw delete allow 3306/tcp;ufw delete allow 6379/tcp;" },
		ufwReload{ "ufw reload" }, ufwDeny{ "ufw deny from " }, ufwDeleteDeny{ "ufw delete deny from " },
		conntrackStr{ "conntrack -D -s " },
		iptablesAllowUDP{ "iptables -D INPUT -p udp -j DROP;service iptables save;service iptables restart;" },
		iptablesBanUDP{ "iptables -I INPUT -p udp -j DROP;service iptables save;service iptables restart;" },
		ufwAllowUDP{ "ufw delete deny proto udp from any to any;ufw reload;" },
		ufwBanUDP{ "ufw deny proto udp from any to any;ufw reload;" }
	;

	//乌班图下需要配合conntrack一起使用，先在ufw建立封禁规则，再用conntrack断掉指定ip的连接
	std::vector<std::string_view>conntrackVec;

	//用于检测系统版本的变量
	const std::string PRETTY{ "PRETTY" }, NAME{ "NAME" }, Alpine{ "Alpine" }, Ubuntu{ "Ubuntu" };
	std::string::const_iterator strBegin, strEnd;
	int thisSystem;           //判断系统类型的变量


	const int
		thousand{ 1000 },
		hundred{ 100 },
		ten{ 10 },
		one{ 1 },
		dateLen{ 19 }                //一组正确的时间字符串的长度，比如2025-05-04T02:14:57
	;


	std::string
		str,                     //用于读取文件保存每一行内容的string
		strDate,                 //保持时间字符串的string 
		strIp,                   //保存IP地址的string
		strBanTypeName,           //保存本次封禁名称的string
		strLoginTypeName         //保存本次登录类型的string
		;

	//要处理的日志文件列表
	//目前发现sftp与scp登录记录也会出现在/var/log/auth.log中，并且两者记录模式一模一样，暂时没有办法区分开，要注意
	//也就是说sftp与scp登录记录与ssh连接记录是会一起累加到ssh连接记录中的
	//要处理的日志文件列表
	const std::string
		authLog{ "/var/log/auth.log" },                //ssh连接记录日志里面记录了sftp与scp登录记录，
		//所以不再需要进行查阅sftp与scp登录记录    
		kern{ "/var/log/kern.log" },                   //3x-ui连接记录日志     
		sftp{ "/var/log/sftp.log" },                   //sftp与scp登录记录
		message{ "/var/log/messages" },                //message日志，无用日志，可以直接清理
		banFile{ "/var/log/banIP" },                   //记录已被封禁IP的信息的文件
		mysqlFile{ "/var/lib/mysql/dengdanjun.log" },    //mysql登录日志   开启日志可参考 https://www.515code.com/posts/9elpj7rs/
		redisFile{ "/var/log/redisLog" },                //魔改版redis 连接密码错误日志
		recordFile{ "/var/log/record" }               //存储可疑记录的文件，当一条日志记录符合检测标准并且不在白名单IP列表中时会被写入到这个文件中
	;

	//file用于读取日志文件
	//filw用于清除日志文件
	//fileBan专门用于封禁IP文件banFile的写入
	//fileRecord专门用于可疑记录文件recordFile的写入
	std::ifstream file;
	std::ofstream filw;
	std::ofstream fileBan;
	std::ofstream fileRecord;
	std::string::const_iterator begin, end, dateBegin, dateEnd, ipBegin, ipEnd, timeBegin, timeEnd, banTypeBegin, banTypeEnd;
	std::tm tm{};
	std::time_t ipTime, currentTime, diff;


	enum ipMapTupleEnum :int
	{
		super_bit = 0,            //综合操作标志位，每一位的值参考bit_Check
		timeString = 1,           //时间值
		ban_type = 2,             //被封禁的类型
		file_pos = 3,             //在文件中的记录位置
		ssh_sftp_scp_time = 4,    //ssh连接输入密码与sftp与scp连接输入密码错误次数
		threeX_ui_time = 5,       //3x-ui面板输入密码错误次数
		mysql_time = 6,           //mysql连接密码错误次数
		redis_time = 7,           //redis连接密码错误次数
		default_time = 8          //无意义项，用于遍历使用，每新增一项统计项需要将此项加1
	};


	enum bit_CheckEnum :int
	{
		has_ban = 0,                //表示是否被封禁  true为已封禁，false为未封禁
		ip_type = 1                 //表示IP是否是IPV4  true为IPV4  false为IPV6
	};

	//系统类型enum
	enum systemTypeEnum :int
	{
		Alpine_system = 0,
		Ubuntu_system = 1,
		unknown_system = 2
	};

	//登录类型
	enum loginTypeEnum : int
	{
		ssh_sftp_scp_login = 0,       //ssh或sftp或scp类型登录
		redis_login = 1,              //redis验证成功
		unknown_login                 //未知登录类型
	};


	//各配置项banTime，前ssh_sftp_scp_time项留空，后面的对应剩余的检查类型,与ipMapTuple中的类型对应
	//比如，第ssh_sftp_scp_time项数值为ssh_sftp_scp类型的banTime，
	//当某一项banTime有数值时，则优先级大于默认banTime
	//当某一项banTime为0时，则以默认banTime为准
	//单位秒
	const int everyBanTime[default_time]{ 0,0,0,0,0,0,0,0 };


	//各配置项findTime，前ssh_sftp_scp_time项留空，后面的对应剩余的检查类型,与ipMapTuple中的类型对应
	//比如，第ssh_sftp_scp_time项数值为ssh_sftp_scp类型的findTime，
	//当某一项findTime有数值时，则优先级大于默认findTime
	//当某一项findTime为0时，则以默认banTime为准
	//单位秒
	const int everyFindTime[default_time]{ 0,0,0,0,0,0,0,0 };



	//各配置项falseTime，前ssh_sftp_scp_time项留空，后面的对应剩余的检查类型,与ipMapTuple中的类型对应
	//比如，第ssh_sftp_scp_time项数值为ssh_sftp_scp类型的falseTime，
	//当某一项falseTime有数值时，则优先级大于默认falseTime
	//当某一项falseTime为0时，则以默认falseTime为准
	//单位一次
	const int everyFalseTime[default_time]{ 0,0,0,0,9,0,0,0 };


	//每一项统计项目是否进行检查，前ssh_sftp_scp_time项留空，后面的对应剩余的检查类型,与ipMapTuple中的类型对应
	//比如，第ssh_sftp_scp_time项数值为ssh_sftp_scp类型是否开启检查的标志位
	const bool everyEnableCHeck[default_time]{ false,false,false,false,true,true,true,true };


	//各配置项IP白名单，前ssh_sftp_scp_time项留空，后面的对应剩余的检查类型,与ipMapTuple中的类型对应
	//比如，第ssh_sftp_scp_time项数值为ssh_sftp_scp类型的IP白名单
	//目前支持IPV4格式点分十进制表示法以及IPV6的冒分十六进制表示法和零压缩表示法以及其CIDR
	//支持单个IP地址写法，比如192.168.255.1   ffff:aaa:1:1:0:0:0:0   ::    ::1  1::2:3:4  
	//支持CIDRIP地址写法，比如192.168.255.0/24   172.16.0.0/12    ffff:aaa:1:1:0:0:0:0/15  ::/1   1::2/123
	//待支持 ipv6 压缩格式  
	const std::vector<std::string>everyIgnoreIp[default_time]{ {},{},{},{},
	{},
	{},
	{},
	{}
	};



	//各配置项文件位置，前ssh_sftp_scp_time项留空，后面的对应剩余的检查类型,与ipMapTuple中的类型对应
	//比如，第ssh_sftp_scp_time项文件名为ssh_sftp_scp类型的记录文件
	const std::string everyFile[default_time]{ "" ,"" ,"" ,"",
		authLog ,kern,mysqlFile,redisFile };


	//预先改变文件权限 确保能够读写的一连串文件
	const std::vector<std::string>chmodFile{ banFile ,sftp ,message ,recordFile,
		authLog ,kern,mysqlFile,redisFile };




	//map的first表示IP地址
	//tuple第0位是综合操作标志位，每一位的值参考bit_Check
	//tuple第1位表示最后操作失败记录的时间
	//累积错误计数使用char表示是为了节省内存开销，这样就算以后添加新的统计项，增加的内存开销也很小
	//tuple第2位表示封禁类型
	//tuple第3位表示记录封禁IP在记录文件中的位置
	//tuple第4位表示ssh与sftp与scp连接输入密码错误次数
	//tuple第5位表示3x-ui面板输入密码错误次数
	//tuple第6位表示mysql输入密码错误次数
	//tuple第7位表示魔改版redis输入密码错误次数
	//为了避免出现大量错误累积时，超越了char的取值范围导致错误，所以当某一项错误计数达到错误设定最大值(falseTime)时便不再累加
	std::unordered_map<std::string, std::tuple<unsigned char, std::time_t, unsigned char, int, std::queue<std::time_t>, std::queue<std::time_t>, std::queue<std::time_t>, std::queue<std::time_t>>>ipMap;
	std::unordered_map<std::string, std::tuple<unsigned char, std::time_t, unsigned char, int, std::queue<std::time_t>, std::queue<std::time_t>, std::queue<std::time_t>, std::queue<std::time_t>>>::iterator ipBegn;


	//默认tuple，增加新的统计项目时只需要修改这里
	const std::tuple<unsigned char, std::time_t, unsigned char, int, std::queue<std::time_t>, std::queue<std::time_t>, std::queue<std::time_t>, std::queue<std::time_t>>defaultTuple{ std::make_tuple(0, 0 ,0,0,std::queue < std::time_t>{},std::queue<std::time_t>{},std::queue<std::time_t>{},std::queue<std::time_t>{}) };
	//实际插入ipMap的tuple
	std::tuple<unsigned char, std::time_t, unsigned char, int, std::queue<std::time_t>, std::queue<std::time_t>, std::queue<std::time_t>, std::queue<std::time_t>>newTuple;


	//检查是否解锁的时间  24小时
	const int
		banTime{ 3600 * 24 },         //默认封禁时间，单位秒
		findTime{ 600 },              //默认findTime,参考fail2ban的findTime，本参数作用和fail2ban的findTime作用相同，单位秒
		//在findTime时间内每一项密码错误次数达到falseTime时，会封禁banTime时间
		banTest{ 120 },               //测试封禁时间，单位秒
		falseTime{ 3 },               //默认最大错误次数，findTime时间内的每一项统计密码输入错误上限
		sleepTime{ 60 }               //检查间隔时间
	;

	int thisBanTime, thisFindTime, thisFalseTime;

	int everyLen, maxSize;
	int maxBanTime;         //最大封禁时间

	//遍历需要的变量
	int i{};

	char lastChar{};

	bool isErase{ true };   //判断是否需要将某IP地址记录移除出ipMap外
	bool isIPV4Save{ false };  //判断iptables是否需要执行save和restart
	bool isIPV6Save{ false };  //判断ip6tables是否需要执行save和restart
	bool isMAx{ false };   //判断每一项错误计数是否达到错误设定最大值
	bool isRun{ false };   //判断是否需要开启程序的标志位
	bool isIgnoreIp;          //判断是否是白名单列表中的IP地址
	bool isIpv4;              //判断是ipv4还是ipv6
	bool isStrIPIPv4;         //判断日志中提取到的地址是否是IPV4
	bool isIgnoreIPIPv4;      //判断中白名单中的地址是否是IPV4
	bool hasUnseal{ false };    //是否执行过解封IP的操作
	bool hasCtlFile{ false };   //是否有执行过文件操作
	bool hasCommand{ false };    //是否执行过system操作
	bool doubleColon{ false };    //判断ipv6中是否出现过两个冒号在一起的情况
	bool isDoubleColon{ false };   //判断ipv6中本次定位的位置是否是两个冒号出现的位置
	bool hasUfwDeny{ false };      //判断ufw是否执行过封禁命令
	bool hasAllowUDP{ false };         //是否已经用命令开启了udp
	bool isFileEmpty{ true };          //判断是否需要清空文件
	const bool enableUDP{ false };    //是否开启udp端口，默认为关闭，自己根据需要设置
	const bool enableMail{ false };   //是否开启发送email的设置项


	////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////程序逻辑（检查阶段）


	//判断当前系统类型
	thisSystem = unknown_system;
	file.open("/etc/os-release", std::ios::binary);
	if (file)
	{
		while (!file.eof())
		{
			getline(file, str);
			if (str.empty())
				continue;

			if (*str.cbegin() != 'N' && *str.cbegin() != 'P')
				continue;

			if (*str.cbegin() == 'N')
			{
				if (str.size() < NAME.size() || !std::equal(str.cbegin(), str.cbegin() + NAME.size(), NAME.cbegin(), NAME.cend()))
					continue;

				strBegin = std::find(str.cbegin() + NAME.size(), str.cend(), '\"');
				if (strBegin == str.cend())
					continue;
			}
			else if (*str.cbegin() == 'P')
			{
				if (str.size() < PRETTY.size() || !std::equal(str.cbegin(), str.cbegin() + PRETTY.size(), PRETTY.cbegin(), PRETTY.cend()))
					continue;

				strBegin = std::find(str.cbegin() + PRETTY.size(), str.cend(), '\"');
				if (strBegin == str.cend())
					continue;
			}

			++strBegin;

			if (strBegin == str.cend())
				continue;

			if (*strBegin != 'A' && *strBegin != 'U')
				continue;

			if (*strBegin == 'A')
			{
				if (std::distance(strBegin, str.cend()) < Alpine.size() || !std::equal(strBegin, strBegin + Alpine.size(), Alpine.cbegin(), Alpine.cend()))
					continue;

				thisSystem = Alpine_system;
				break;
			}
			else if (*strBegin == 'U')
			{
				if (std::distance(strBegin, str.cend()) < Ubuntu.size() || !std::equal(strBegin, strBegin + Ubuntu.size(), Ubuntu.cbegin(), Ubuntu.cend()))
					continue;

				thisSystem = Ubuntu_system;
				break;
			}
		}
		file.close();
	}
	//目前仅支持Alpine 封禁与解封命令，计划加入Ubuntu，已经摸透了ufw操作规则
	if (thisSystem != Alpine_system && thisSystem != Ubuntu_system)
		return -1;






	//检查是否有项目设置了检查标志位
	for (i = ssh_sftp_scp_time; i != default_time; ++i)
	{
		if (everyEnableCHeck[i])
		{
			isRun = true;
			break;
		}
	}

	//所有检查项均不需要检查，所以终止程序运行
	if (!isRun)
		return -2;

	//检查IP白名单列表是否是合法的IP或者CIDR 
	//支持IPV4和UIPV6
	for (i = ssh_sftp_scp_time; i != default_time; ++i)
	{
		for (vecBegin = everyIgnoreIp[i].cbegin(); vecBegin != everyIgnoreIp[i].cend(); ++vecBegin)
		{
			doubleColon = isDoubleColon = false;
			ipBegin = vecBegin->cbegin(), ipEnd = vecBegin->cend();

			if (std::distance(ipBegin, ipEnd) < ipv6MixLen || std::distance(ipBegin, ipEnd) > ipv6MaxLen)
				goto invaildIp;



			checkBegin = std::find_if(ipBegin, ipEnd, [](const char ch)
			{
				return ((ch >= '0' && ch <= '9')
					|| (ch >= 'a' && ch <= 'f')
					|| (ch >= 'A' && ch <= 'F')
					|| ch == ':');
			});
			if (checkBegin != ipBegin)
				goto invaildIp;

			if (*checkBegin == ':')
			{
				if (*(checkBegin + 1) != ':')
					goto invaildIp;
				else
				{
					doubleColon = true;
					isDoubleColon = true;
					isIpv4 = false;
					checkBegin += 2;
					ipBegin = checkBegin;
				}
			}

			if (!doubleColon)
			{

				checkEnd = std::find_if_not(checkBegin + 1, ipEnd, [](const char ch)
				{
					return ((ch >= '0' && ch <= '9')
						|| (ch >= 'a' && ch <= 'f')
						|| (ch >= 'A' && ch <= 'F'));
				});

				if (checkEnd == ipEnd)
					goto invaildIp;

				if (*checkEnd != '.' && *checkEnd != ':')
					goto invaildIp;

				if (*checkEnd == '.')
					isIpv4 = true;
				else
					isIpv4 = false;

				if (isIpv4 && (std::distance(checkBegin, checkEnd) > ipv4NumMaxLen ||
					std::any_of(checkBegin, checkEnd,
						std::bind(std::logical_not<bool>(),
							std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9'))))))
					goto invaildIp;
				else if (!isIpv4 && std::distance(checkBegin, checkEnd) > ipv6NumMaxLen)
					goto invaildIp;


				if (isIpv4)
				{
					f3 = 0.1f;
					sum = std::accumulate(std::make_reverse_iterator(checkEnd),
						std::make_reverse_iterator(checkBegin), 0,
						[&f3, f2](int sum, int everyChar)
					{
						f3 *= f2;
						return sum += (everyChar - '0') * (static_cast<int>(f3));
					});

					if ((sum < 0 || sum > 255))
						goto invaildIp;
				}

				ipBegin = checkEnd;
				if (ipBegin != ipEnd)
					++ipBegin;
			}

			//IPV4地址判断分支
			if (isIpv4)
			{
				for (j = 1; j != 5; ++j)
				{
					checkBegin = std::find_if(ipBegin, ipEnd,
						std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9')));

					if (checkBegin != ipBegin)
						goto invaildIp;

					checkEnd = std::find_if_not(checkBegin + 1, ipEnd,
						std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9')));

					if (std::distance(checkBegin, checkEnd) > ipv4NumMaxLen)
						goto invaildIp;

					if (j < 3 && (checkEnd == ipEnd || *checkEnd != '.'))
						goto invaildIp;
					else if (j == 3 && (checkEnd != ipEnd && *checkEnd != '/'))
						goto invaildIp;
					else if (j == 4 && checkEnd != ipEnd)
						goto invaildIp;

					f3 = 0.1f;
					sum = std::accumulate(std::make_reverse_iterator(checkEnd),
						std::make_reverse_iterator(checkBegin), 0,
						[&f3, f2](int sum, int everyChar)
					{
						f3 *= f2;
						return sum += (everyChar - '0') * (static_cast<int>(f3));
					});

					if (j < 4 && (sum < 0 || sum > 255))
						goto invaildIp;
					else if (j == 4 && (sum < 0 || sum > 32))
						goto invaildIp;
					else if (j > 2 && checkEnd == ipEnd)
						break;


					ipBegin = checkEnd;
					if (*checkEnd == '/' && checkEnd + 1 == ipEnd)
						goto invaildIp;
					if (ipBegin != ipEnd)
						++ipBegin;

					if (j > 2 && ipBegin == ipEnd)
						break;
					else if (j == 4 && ipBegin != ipEnd)
						goto invaildIp;
				}
			}
			else    //IPV6地址判断分支
			{
				lastChar = 0;
				for (j = 1; j != 9; ++j)
				{
					if (j < 8)
					{
						if (isDoubleColon && (ipBegin == ipEnd))
							break;



						if (ipBegin != ipEnd && *ipBegin == ':')
						{
							if (doubleColon)
								goto invaildIp;
							else
							{
								doubleColon = true;
								isDoubleColon = true;
								checkBegin = ipBegin + 1;
								ipBegin = checkBegin;
								continue;
							}
						}


						if (isDoubleColon && ipBegin == ipEnd)
							break;

						if (*ipBegin == '/' && ipBegin + 1 == ipEnd)
							goto invaildIp;

						if (*ipBegin != '/')
						{
							if (lastChar != '/')
							{
								checkBegin = std::find_if(ipBegin, ipEnd, [](const char ch)
								{
									return ((ch >= '0' && ch <= '9')
										|| (ch >= 'a' && ch <= 'f')
										|| (ch >= 'A' && ch <= 'F'));
								});


								if (checkBegin != ipBegin)
									goto invaildIp;

								checkEnd = std::find_if_not(checkBegin + 1, ipEnd, [](const char ch)
								{
									return ((ch >= '0' && ch <= '9')
										|| (ch >= 'a' && ch <= 'f')
										|| (ch >= 'A' && ch <= 'F'));
								});

								if (std::distance(checkBegin, checkEnd) > ipv6NumMaxLen)
									goto invaildIp;
							}
							else
							{
								checkBegin = std::find_if(ipBegin, ipEnd,
									std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9')));


								if (checkBegin != ipBegin)
									goto invaildIp;

								checkEnd = std::find_if_not(checkBegin + 1, ipEnd,
									std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9')));

								if (std::distance(checkBegin, checkEnd) > 3 || checkEnd != ipEnd)
									goto invaildIp;

								f3 = 0.1f;
								sum = std::accumulate(std::make_reverse_iterator(checkEnd),
									std::make_reverse_iterator(checkBegin), 0,
									[&f3, f2](int sum, int everyChar)
								{
									f3 *= f2;
									return sum += (everyChar - '0') * (static_cast<int>(f3));
								});

								if ((sum < 0 || sum > 128))
									goto invaildIp;
								break;

							}
						}
						else
						{
							checkBegin = std::find_if(ipBegin + 1, ipEnd,
								std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9')));


							if (checkBegin != ipBegin + 1)
								goto invaildIp;

							checkEnd = std::find_if_not(checkBegin + 1, ipEnd,
								std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9')));


							if (std::distance(checkBegin, checkEnd) > ipv6NumMaxLen || checkEnd != ipEnd)
								goto invaildIp;

						}

						if (lastChar == '/')
						{
							f3 = 0.1f;
							sum = std::accumulate(std::make_reverse_iterator(checkEnd),
								std::make_reverse_iterator(checkBegin), 0,
								[&f3, f2](int sum, int everyChar)
							{
								f3 *= f2;
								return sum += (everyChar - '0') * (static_cast<int>(f3));
							});

							if ((sum < 0 || sum > 128))
								goto invaildIp;
						}

						if (checkEnd != ipEnd)
							lastChar = *checkEnd;

					}
					else
					{
						checkBegin = std::find_if(ipBegin, ipEnd,
							std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9')));

						if (checkBegin != ipBegin)
							goto invaildIp;

						checkEnd = std::find_if_not(checkBegin + 1, ipEnd,
							std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9')));

						if (std::distance(checkBegin, checkEnd) > ipv6NumMaxLen - 1)
							goto invaildIp;

						if (checkEnd != ipEnd)
							goto invaildIp;

						f3 = 0.1f;
						sum = std::accumulate(std::make_reverse_iterator(checkEnd),
							std::make_reverse_iterator(checkBegin), 0,
							[&f3, f2](int sum, int everyChar)
						{
							f3 *= f2;
							return sum += (everyChar - '0') * (static_cast<int>(f3));
						});

						if ((sum < 0 || sum > 128))
							goto invaildIp;
						else
							break;
					}

					if (doubleColon && checkEnd == ipEnd)
					{
						if (lastChar == '/')
						{
							f3 = 0.1f;
							sum = std::accumulate(std::make_reverse_iterator(checkEnd),
								std::make_reverse_iterator(checkBegin), 0,
								[&f3, f2](int sum, int everyChar)
							{
								f3 *= f2;
								return sum += (everyChar - '0') * (static_cast<int>(f3));
							});

							if ((sum < 0 || sum > 128))
								goto invaildIp;
						}
						else if (*ipBegin == '/')
						{
							checkBegin = std::find_if(ipBegin + 1, ipEnd,
								std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9')));

							if (checkBegin != ipBegin + 1)
								goto invaildIp;

							checkEnd = std::find_if_not(checkBegin + 1, ipEnd,
								std::bind(std::logical_and<bool>(), std::bind(std::greater_equal<char>(), std::placeholders::_1, '0'), std::bind(std::less_equal<char>(), std::placeholders::_1, '9')));

							if (std::distance(checkBegin, checkEnd) > 3)
								goto invaildIp;

							f3 = 0.1f;
							sum = std::accumulate(std::make_reverse_iterator(checkEnd),
								std::make_reverse_iterator(checkBegin), 0,
								[&f3, f2](int sum, int everyChar)
							{
								f3 *= f2;
								return sum += (everyChar - '0') * (static_cast<int>(f3));
							});

							if ((sum < 0 || sum > 128))
								goto invaildIp;
						}
						break;
					}
					else if (!doubleColon &&  j < 7 && (checkEnd == ipEnd || *checkEnd != ':'))
						goto invaildIp;
					else if (j == 7 && (checkEnd != ipEnd && *checkEnd != '/'))
						goto invaildIp;
					else if (j > 6 && checkEnd == ipEnd)
						break;

					if (j == 8)
					{
						f3 = 0.1f;
						sum = std::accumulate(std::make_reverse_iterator(checkEnd),
							std::make_reverse_iterator(checkBegin), 0,
							[&f3, f2](int sum, int everyChar)
						{
							f3 *= f2;
							return sum += (everyChar - '0') * (static_cast<int>(f3));
						});

						if ((sum < 0 || sum > 128))
							goto invaildIp;
					}

					ipBegin = checkEnd;
					if (*checkEnd == '/' && checkEnd + 1 == ipEnd)
						goto invaildIp;
					if (ipBegin != ipEnd)
						++ipBegin;

					if (j > 6 && ipBegin == ipEnd)
						break;
					else if (j == 8 && ipBegin != ipEnd)
						goto invaildIp;

					isDoubleColon = false;
				}
			}
		}
	}
	goto vaildIp;

	//IP白名单列表中存在非法的IP或者CIDR，所以终止程序运行
invaildIp:
	return -3;


vaildIp:;



	//检查邮箱发送相关的字符串是否为空以及发送buffer大小能否满足要求
	if (enableMail)
	{
		if (ColaKeyHeader.empty() || tomailHeader.empty() || fromTitleHeader.empty() || subjectHeader.empty() ||
			smtpCodeHeader.empty() || smtpEmailHeader.empty() || smtpCodeTypeHeader.empty() || isTextContentHeader.empty() ||
			contentHeader.empty() || emailBack.empty() || ColaKey.empty() || tomail.empty() || fromTitle.empty() ||
			subject.empty() || smtpCode.empty() || smtpEmail.empty() || smtpCodeType.empty() || isTextContent.empty())
			return -4;


		sendPos = sendBuf;
		std::copy(ColaKeyHeader.cbegin(), ColaKeyHeader.cend(), sendPos);
		sendPos += ColaKeyHeader.size();
		std::copy(ColaKey.cbegin(), ColaKey.cend(), sendPos);
		sendPos += ColaKey.size();
		std::copy(tomailHeader.cbegin(), tomailHeader.cend(), sendPos);
		sendPos += tomailHeader.size();
		std::copy(tomail.cbegin(), tomail.cend(), sendPos);
		sendPos += tomail.size();
		std::copy(fromTitleHeader.cbegin(), fromTitleHeader.cend(), sendPos);
		sendPos += fromTitleHeader.size();
		std::copy(fromTitle.cbegin(), fromTitle.cend(), sendPos);
		sendPos += fromTitle.size();
		std::copy(subjectHeader.cbegin(), subjectHeader.cend(), sendPos);
		sendPos += subjectHeader.size();
		std::copy(subject.cbegin(), subject.cend(), sendPos);
		sendPos += subject.size();
		std::copy(smtpCodeHeader.cbegin(), smtpCodeHeader.cend(), sendPos);
		sendPos += smtpCodeHeader.size();
		std::copy(smtpCode.cbegin(), smtpCode.cend(), sendPos);
		sendPos += smtpCode.size();
		std::copy(smtpEmailHeader.cbegin(), smtpEmailHeader.cend(), sendPos);
		sendPos += smtpEmailHeader.size();
		std::copy(smtpEmail.cbegin(), smtpEmail.cend(), sendPos);
		sendPos += smtpEmail.size();
		std::copy(smtpCodeTypeHeader.cbegin(), smtpCodeTypeHeader.cend(), sendPos);
		sendPos += smtpCodeTypeHeader.size();
		std::copy(smtpCodeType.cbegin(), smtpCodeType.cend(), sendPos);
		sendPos += smtpCodeType.size();
		std::copy(isTextContentHeader.cbegin(), isTextContentHeader.cend(), sendPos);
		sendPos += isTextContentHeader.size();
		std::copy(isTextContent.cbegin(), isTextContent.cend(), sendPos);
		sendPos += isTextContent.size();
		std::copy(contentHeader.cbegin(), contentHeader.cend(), sendPos);
		sendPos += contentHeader.size();
		if (sendPos != mixSendPos)
			return -5;



		curl_global_init(CURL_GLOBAL_DEFAULT);
		curl = curl_easy_init();
		if (!curl)
			return -6;

		// 设置目标URL
		curl_easy_setopt(curl, CURLOPT_URL, "https://luckycola.com.cn/tools/customMail");

		// 设置为POST请求
		curl_easy_setopt(curl, CURLOPT_POST, 1L);



		//设置header
		headers = curl_slist_append(headers, "Content-Type: application/json");
		headers = curl_slist_append(headers, "Connection: keep-alive");
		headers = curl_slist_append(headers, "Keep-Alive: timeout=99999, max=99999");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

		// SSL验证设置
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true); // 测试时可禁用验证
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);

		// 启用keep-alive
		curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

		// 设置keep-alive的时间间隔（单位为秒）
		curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, sleepTime - 1); // 例如，60秒无活动后发送keep-alive消息
		curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, sleepTime - 1); // 例如，每60秒发送一次keep-alive消息


		// 设置响应回调
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, reinterpret_cast<void*>(&curlPack));
	}




	//检查用于装载命令的缓冲区是否有足够的长度

	everyLen = maxSize = 0;
	if (!chmodFile.empty())
	{
		for (i = 0; i != chmodFile.size(); ++i)
		{
			everyLen = static_cast<int>(strchmod.size() + chmodFile[i].size() + 1);
			if (maxSize < everyLen)
				maxSize = everyLen;
		}
		everyLen = static_cast<int>(strIptables_I.size() + strDrop.size() + ipv6MaxLen + 1);
		if (maxSize < everyLen)
			maxSize = everyLen;
		if (commandBufLen < maxSize)
			return -7;
	}


	//检查banFile是否存在，不存在则创建
	file.open(banFile, std::ios::binary);
	if (!file)
	{
		filw.open(banFile, std::ios::trunc | std::ios::binary);
		if (!filw)
			return -8;
		filw << "";
		filw.close();
	}
	else
		file.close();


	//检查recordFile是否存在，不存在则创建
	file.open(recordFile, std::ios::binary);
	if (!file)
	{
		filw.open(recordFile, std::ios::app | std::ios::binary);
		if (!filw)
			return -9;
		filw << "";
		filw.close();
	}
	else
		file.close();

	//用于检测sendBuf到mixSendPos之间位置的数据是否准确的string变量
	const std::string curlCheckStr{ sendBuf ,const_cast<char*>(mixSendPos) };


	/////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////程序逻辑（正式运行阶段）



	//等待其他系统服务启动，先休眠60s
	std::this_thread::sleep_for(std::chrono::seconds(sleepTime));


	//根据标志位判断是否开启udp
	switch (thisSystem)
	{
	case Alpine_system:
		system(iptablesAllowUDP.c_str());
		if (!enableUDP)
			system(iptablesBanUDP.c_str());
		break;

	case Ubuntu_system:
		system(ufwAllowUDP.c_str());
		if (!enableUDP)
			system(ufwBanUDP.c_str());
		break;

	default:
		break;
	}




	//改变文件读写权限
	//检测iptables规则日志，ssh连接记录日志，3x-ui连接记录日志权限改为666，方便程序读写
	if (!chmodFile.empty())
	{
		pos = commandBuf;
		std::copy(strchmod.cbegin(), strchmod.cend(), pos);
		for (i = 0; i != chmodFile.size(); ++i)
		{
			if (!chmodFile[i].empty())
			{
				pos = commandBuf + strchmod.size();
				std::copy(chmodFile[i].cbegin(), chmodFile[i].cend(), pos);
				pos += chmodFile[i].size();
				*pos = '\0';
				system(commandBuf);
			}
		}
	}


	//先清空掉相关日志文件的所有记录，以后检查时只需要获取一次当前时间，以当前时间为日志时间戳即可，
	// 提升性能的同时，可以解决各日志文件时区不一致的问题
	for (i = ssh_sftp_scp_time; i != default_time; ++i)
	{
		if (everyEnableCHeck[i] && !everyFile[i].empty())
		{
			file.open(everyFile[i], std::ios::binary);
			if (file)
			{
				file.close();
				filw.open(everyFile[i], std::ios::trunc | std::ios::binary);
				if (filw)
				{
					filw << "";
					filw.close();
				}
			}
		}
	}


	//从封禁IP文件中还原信息到ipMap中
	file.open(banFile, std::ios::binary);
	if (file)
	{
		while (!file.eof())
		{
			getline(file, str);
			if (str.empty())
				continue;

			begin = std::find(str.cbegin(), str.cend(), ' ');
			if (begin == str.cbegin())
				continue;

			//确定IP范围
			ipBegin = str.cbegin(), ipEnd = begin;

			begin = std::find_if(begin + 1, str.cend(), std::bind(std::not_equal_to<>(), std::placeholders::_1, ' '));
			if (begin == str.cbegin())
				continue;

			end = std::find(begin + 1, str.cend(), ' ');
			if (end == str.cbegin())
				continue;

			//确定time_t范围
			timeBegin = begin, timeEnd = end;

			begin = std::find_if(end + 1, str.cend(), std::bind(std::not_equal_to<>(), std::placeholders::_1, ' '));
			if (begin == str.cbegin())
				continue;

			//确定封禁类型范围
			banTypeBegin = begin, banTypeEnd = str.cend();

			strIp.assign(ipBegin, ipEnd);

			//插入记录到ipMap中
			ipBegn = ipMap.find(strIp);
			if (ipBegn == ipMap.cend())
			{
				begin = std::find_if(strIp.cbegin(), strIp.cend(),
					std::bind(std::logical_or<>(), std::bind(std::equal_to<>(), std::placeholders::_1, '.'), std::bind(std::equal_to<>(), std::placeholders::_1, ':')));
				if (begin == strIp.cend())
					continue;

				if (*begin == '.')
					isIpv4 = true;
				else
					isIpv4 = false;

				f3 = 0.1f;
				ipTime = std::accumulate(std::make_reverse_iterator(timeEnd),
					std::make_reverse_iterator(timeBegin), 0,
					[&f3, f2](int sum, int everyChar)
				{
					f3 *= f2;
					return sum += (everyChar - '0') * (static_cast<int>(f3));
				});


				//将时间戳  Ip类型  是否被封禁  封禁类型等信息插入ipMap中
				newTuple = defaultTuple;
				std::get<timeString>(newTuple) = ipTime;
				bit = std::get<super_bit>(newTuple);
				bit.set(ip_type, isIpv4);
				bit.set(has_ban, true);
				std::get<super_bit>(newTuple) = static_cast<unsigned char>(bit.to_ulong());
				std::get<ban_type>(newTuple) = *banTypeBegin;
				ipMap.insert(std::make_pair(strIp, newTuple));
			}
		}
		file.close();
	}


	//从ipMap中重建信息进banFile中
	fileBan.open(banFile, std::ios::out | std::ios::binary);
	if (!fileBan)
		return -8;
	if (!ipMap.empty())
	{
		for (ipBegn = ipMap.begin(); ipBegn != ipMap.end(); ++ipBegn)
		{
			beginPos = fileBan.tellp();
			//写入IP地址  时间戳  封禁类型等信息到banFile中
			fileBan << ipBegn->first << ' ' << std::get<timeString>(ipBegn->second) << ' ' << std::get<ban_type>(ipBegn->second) << '\n';
			//将本次IP地址在文件中的位置设置到ipMap中
			std::get<file_pos>(ipBegn->second) = beginPos;
		}
		// 将文件指针移动到文件末尾
		fileBan.seekp(0, std::ios::end);
		fileBan.flush();
	}


	//打开recordFile，准备记录可疑记录信息
	fileRecord.open(recordFile, std::ios::binary | std::ios::app);
	if (!fileRecord)
		return -9;




	//循环执行代码
	while (true)
	{


		//在以下循环中hasCtlFile表示recordFile是否执行过写入操作
		hasCtlFile = false;
		sendPos = const_cast<char*>(mixSendPos);
		hasAllowUDP = false;
		currentTime = std::time(nullptr);
		//直接将currentTime赋值给ipTime，提升性能，
		// 并且解决不同日志文件时区可能不一致的问题
		ipTime = currentTime;
		for (i = ssh_sftp_scp_time; i != default_time; ++i)
		{

			if (everyEnableCHeck[i] && !everyFile[i].empty())
			{
				//每次读取文件前获取当前时间戳，如果时间解析失败则将该时间戳赋值给ipTime

				file.open(everyFile[i], std::ios::binary);
				if (file)
				{
					//判断文件内容是否为空
					isFileEmpty = true;

					//在这里获取每一配置项的falseTime，每个类型的数据获取一次即可，略微提升性能
					thisFalseTime = everyFalseTime[i];
					if (!thisFalseTime)
						thisFalseTime = falseTime;

					while (!file.eof())
					{
						std::getline(file, str);
						if (str.empty())
							continue;

						//存在内容则文件不为空
						isFileEmpty = false;

						//设置登录类型为默认值
						thisLoginType = unknown_login;

						//各配置项文件不同的解析
						switch (i)
						{
							// 检查ssh连接记录日志与sftp与scp登录记录
						case ssh_sftp_scp_time:

							//dateBegin指向时间字符串的开始，dateEnd指向时间字符串的末尾
							dateBegin = str.cbegin();
							dateEnd = std::find(dateBegin + 1, str.cend(), '.');
							if (dateEnd == str.cend())
								continue;

							begin = std::find_if(dateEnd + 1, str.cend(), std::bind(std::logical_or<bool>(),
								std::bind(std::equal_to<>(), std::placeholders::_1, 'A'), std::bind(std::equal_to<>(), std::placeholders::_1, 'F')));
							if (begin == str.cend())
								continue;

							if (*begin == 'A')
							{
								//判断是否是登陆成功记录
								if (std::distance(begin, str.cend()) < strAccept.size() ||
									!std::equal(begin, begin + strAccept.size(), strAccept.cbegin(), strAccept.cend()))
									continue;

								//将本条日志记录追加到recordFile中保存，方便以后查看登录记录
								fileRecord << str << '\n';
								hasCtlFile = true;
								if (!enableMail)
									continue;
								end = begin + strAccept.size();
								thisLoginType = ssh_sftp_scp_login;
								strLoginTypeName = "ssh_sftp_scp";
							}
							else
							{
								//判断是否是登陆失败记录
								if (std::distance(begin, str.cend()) < strFail.size() ||
									!std::equal(begin, begin + strFail.size(), strFail.cbegin(), strFail.cend()))
									continue;

								end = begin + strFail.size();
							}


							begin = search(std::make_reverse_iterator(str.cend()), std::make_reverse_iterator(end),
								std::make_reverse_iterator(strFrom.cend()), std::make_reverse_iterator(strFrom.cbegin())).base();
							if (begin == std::make_reverse_iterator(end).base())
								continue;

							begin = std::find_if(begin + 1, str.cend(), [](const char ch)
							{
								return ((ch >= '0' && ch <= '9')
									|| (ch >= 'a' && ch <= 'f')
									|| (ch >= 'A' && ch <= 'F'));
							});
							if (begin == str.cend())
								continue;

							//begin指向ip字符串的开始，end指向ip字符串的结尾
							end = std::find(begin + 1, str.cend(), ' ');
							if (end == str.cend())
								continue;
							break;

							//检查3x-ui连接记录日志
						case threeX_ui_time:

							//dateBegin指向时间字符串的开始，dateEnd指向时间字符串的末尾
							dateBegin = str.cbegin();
							dateEnd = std::find(dateBegin + 1, str.cend(), '.');
							if (dateEnd == str.cend())
								continue;

							begin = search(dateEnd + 1, str.cend(), strxui.cbegin(), strxui.cend());
							if (begin == str.cend())
								continue;
							begin = search(begin + strxui.size(), str.cend(), strWrong.cbegin(), strWrong.cend());
							if (begin == str.cend())
								continue;

							end = begin + strWrong.size();
							begin = std::search(std::make_reverse_iterator(str.cend()), std::make_reverse_iterator(end),
								std::make_reverse_iterator(strFindIP.cend()), std::make_reverse_iterator(strFindIP.cbegin())).base();
							if (begin == std::make_reverse_iterator(end).base())
								continue;

							begin = std::find_if(begin + 1, str.cend(), [](const char ch)
							{
								return ((ch >= '0' && ch <= '9')
									|| (ch >= 'a' && ch <= 'f')
									|| (ch >= 'A' && ch <= 'F'));
							});
							if (begin == str.cend())
								continue;

							//begin指向ip字符串的开始，end指向ip字符串的结尾
							end = find(begin + 1, str.cend(), '\"');
							if (end == str.cend())
								continue;

							break;

							//检查mysql连接记录日志
						case mysql_time:

							//dateBegin指向时间字符串的开始，dateEnd指向时间字符串的末尾
							dateBegin = str.cbegin();
							dateEnd = std::find(dateBegin + 1, str.cend(), '.');
							if (dateEnd == str.cend())
								continue;

							begin = search(dateEnd + 1, str.cend(), strAccessDen.cbegin(), strAccessDen.cend());
							if (begin == str.cend())
								continue;

							end = begin + strAccessDen.size();


							begin = std::find_if(std::make_reverse_iterator(str.cend()), std::make_reverse_iterator(end),
								std::bind(std::logical_or<bool>(),
									std::bind(std::equal_to<>(), std::placeholders::_1, 'S'), std::bind(std::equal_to<>(), std::placeholders::_1, 'O'))).base();
							if (begin == std::make_reverse_iterator(end).base())
								continue;

							--begin;
							if (*begin == 'O')
								continue;

							begin = std::find(std::make_reverse_iterator(begin), std::make_reverse_iterator(end), '@').base();
							if (begin == std::make_reverse_iterator(end).base())
								continue;

							begin = find(begin, str.cend(), '\'');
							if (begin == str.cend())
								continue;
							++begin;
							if (begin == str.cend())
								continue;

							//begin指向ip字符串的开始，end指向ip字符串的结尾
							end = find(begin + 1, str.cend(), '\'');
							if (end == str.cend())
								continue;

							break;
							//检查魔改版redis连接记录日志
						case redis_time:

							//dateBegin指向时间字符串的开始，dateEnd指向时间字符串的末尾
							dateBegin = std::find(str.cbegin(), str.cend(), ' ');
							if (dateBegin == str.cend())
								continue;
							++dateBegin;
							if (dateBegin == str.cend())
								continue;

							dateEnd = std::find(dateBegin + 1, str.cend(), '.');
							if (dateEnd == str.cend())
								continue;

							begin = search(dateEnd + 1, str.cend(), strAccess.cbegin(), strAccess.cend());
							if (begin == str.cend())
								continue;

							begin = std::find_if(begin + strAccess.size(), str.cend(),
								std::bind(std::logical_or<bool>(), std::bind(std::equal_to<>(), std::placeholders::_1, 's'), std::bind(std::equal_to<>(), std::placeholders::_1, 'f')));
							if (begin == str.cend())
								continue;

							if (*begin == 's')
							{
								//判断是否是密码验证成功记录
								if (std::distance(begin, str.cend()) < strSuccess.size() ||
									!std::equal(begin, begin + strSuccess.size(), strSuccess.cbegin(), strSuccess.cend()))
									continue;

								//将本条日志记录追加到recordFile中保存，方便以后查看登录记录
								fileRecord << str << '\n';
								hasCtlFile = true;
								if (!enableMail)
									continue;
								begin = begin + strSuccess.size();
								thisLoginType = redis_login;
								strLoginTypeName = "redis";
							}
							else
							{
								//判断是否是密码验证失败记录
								if (std::distance(begin, str.cend()) < strFailed.size() ||
									!std::equal(begin, begin + strFailed.size(), strFailed.cbegin(), strFailed.cend()))
									continue;

								begin = begin + strFailed.size();
							}

							begin = search(begin, str.cend(), straddr.cbegin(), straddr.cend());
							if (begin == str.cend())
								continue;

							begin += straddr.size();

							//begin指向ip字符串的开始，end指向ip字符串的结尾
							end = std::find(std::make_reverse_iterator(str.cend()), std::make_reverse_iterator(begin), ':').base();
							if (end == std::make_reverse_iterator(begin).base())
								continue;
							--end;

							break;


							//未知类型
						default:

							break;
						}


						//确定IP字符串
						strIp.assign(begin, end);

						//如果启动发送email的功能
						if (enableMail && thisLoginType != unknown_login)
						{
							//如果已经处理过本次登录ip则跳过
							if (loginIpSet.find(strIp) != loginIpSet.cend())
								continue;

							//没有处理过，插入本次登录ip，方便以后进行查询
							loginIpSet.insert(strIp);


							//检查剩余长度是否足够
							if (std::distance(sendPos, sendBuf + sendBufLen) < 100)
							{
								//检测sendBuf到mixSendPos之间的数据是否被改过
								if (!std::equal(curlCheckStr.cbegin(), curlCheckStr.cend(), sendBuf, const_cast<char*>(mixSendPos)))
									std::copy(curlCheckStr.cbegin(), curlCheckStr.cend(), sendBuf);
								std::copy(emailBack.cbegin(), emailBack.cend(), sendPos);
								sendPos += emailBack.size();
								*sendPos++ = '\0';


								//使用curl调用邮件api	
								curlPack.curlPos = 0;
								curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sendBuf);

								//因为发送邮件接口需要进行DNS解析，所以需要开启udp服务
								if (!enableUDP && !hasAllowUDP)
								{
									switch (thisSystem)
									{
									case Alpine_system:
										system(iptablesAllowUDP.c_str());
										break;
									case Ubuntu_system:
										system(ufwAllowUDP.c_str());
										break;
									default:
										break;
									}
									hasAllowUDP = true;
								}

								// 执行请求
								res = curl_easy_perform(curl);

								sendPos = const_cast<char*>(mixSendPos);
							}
							if (!strIp.empty())
							{
								std::copy(loginIP.cbegin(), loginIP.cend(), sendPos);
								sendPos += loginIP.size();
								std::copy(strIp.cbegin(), strIp.cend(), sendPos);
								sendPos += strIp.size();
								*sendPos++ = ' ';
							}
							if (!strLoginTypeName.empty())
							{
								std::copy(loginType.cbegin(), loginType.cend(), sendPos);
								sendPos += loginType.size();
								std::copy(strLoginTypeName.cbegin(), strLoginTypeName.cend(), sendPos);
								sendPos += strLoginTypeName.size();
								*sendPos++ = ' ';
							}

							continue;
						}



						//判断IP字符串是IPV4还是IPV6
						begin = std::find_if(strIp.cbegin(), strIp.cbegin() + 5,
							std::bind(std::logical_or<bool>(), std::bind(std::equal_to<char>(), std::placeholders::_1, '.'), std::bind(std::equal_to<char>(), std::placeholders::_1, ':')));
						if (begin == strIp.cbegin() + 5)
							continue;

						if (*begin == '.')
							isStrIPIPv4 = true;
						else
							isStrIPIPv4 = false;

						//判断strIp是否在白名单IP列表中
						isIgnoreIp = false;
						if (!everyIgnoreIp[i].empty())
						{
							for (ignoreIpBegin = everyIgnoreIp[i].cbegin();
								ignoreIpBegin != everyIgnoreIp[i].cend(); ++ignoreIpBegin)
							{
								//判断白名单IP字符串是IPV4还是IPV6
								begin = std::find_if(ignoreIpBegin->cbegin(), ignoreIpBegin->cbegin() + 5,
									std::bind(std::logical_or<bool>(), std::bind(std::equal_to<char>(), std::placeholders::_1, '.'), std::bind(std::equal_to<char>(), std::placeholders::_1, ':')));
								if (begin == ignoreIpBegin->cbegin() + 5)
									continue;

								if (*begin == '.')
									isIgnoreIPIPv4 = true;
								else
									isIgnoreIPIPv4 = false;

								//只有当strIp与ignoreIpBegin属于同一类型的IP才进行处理，否则跳过
								if (!((isStrIPIPv4 && isIgnoreIPIPv4) || (!isStrIPIPv4 && !isIgnoreIPIPv4)))
									continue;

								//判断本次ignoreIpBegin是否是非CIDR IP
								if (*(ignoreIpBegin->cend() - 2) != '/' && *(ignoreIpBegin->cend() - 3) != '/' && *(ignoreIpBegin->cend() - 4) != '/')
								{
									if (std::equal(strIp.cbegin(), strIp.cend(), ignoreIpBegin->cbegin(), ignoreIpBegin->cend()))
									{
										isIgnoreIp = true;
										break;
									}
									else
										continue;
								}






								//判断IPV4 是否在CIDR范围
								if (isStrIPIPv4 && isIgnoreIPIPv4)
								{

									std::copy(ignoreIpBegin->cbegin(), ignoreIpBegin->cend(), commandBuf);
									commandBuf[ignoreIpBegin->size()] = '\0';
									pos = std::find(commandBuf, commandBuf + ignoreIpBegin->size(), '/');
									if (pos == commandBuf + ignoreIpBegin->size())
										continue;
									*pos = '\0';

									val = ntohl(inet_addr(commandBuf)); // little endian
									msk = atoi(pos + 1);
									offset = 32 - msk;

									tar = ntohl(inet_addr(strIp.c_str()));

									if ((val >> offset) == (tar >> offset))
									{
										isIgnoreIp = true;
										break;
									}

									isIgnoreIp = false;
									break;

								}              //判断IPV6 是否在CIDR范围
								else if (!isStrIPIPv4 && !isIgnoreIPIPv4)
								{

									// 将IPv6地址和CIDR转换为二进制格式
									if (inet_pton(AF_INET6, strIp.c_str(), &ipv6) != 1)
									{
										isIgnoreIp = false;
										break;
									}
									if (inet_pton(AF_INET6, ignoreIpBegin->c_str(), &net) != 1)
									{
										// 尝试从CIDR字符串中分离出网络地址和前缀长度
										ptr = const_cast<char*>(ignoreIpBegin->c_str());
										if (inet_pton(AF_INET6, strtok(ptr, "/"), &net) != 1)
										{
											isIgnoreIp = false;
											break;
										}
										prefix = strtol(strtok(nullptr, "/"), nullptr, 10);
									}
									else
									{
										// 如果CIDR字符串中没有'/'，则默认为/128
										prefix = 128;
									}

									// 将网络地址和前缀长度转换为位掩码形式
									mask[16] = { 0 };  // 128 bits for IPv6
									for (i = 0; i < prefix / 8; ++i)
										mask[i] = 0xFF;  // Set first bytes to 0xFF
									mask[prefix / 8] = 0xFF << (8 - prefix % 8);  // Set remaining bits in last byte

									// 检查IP地址是否在CIDR范围内
									for (i = 0; i < 16; ++i)
									{
										if ((ipv6.s6_addr[i] & mask[i]) != (net.s6_addr[i] & mask[i]))
										{
											isIgnoreIp = false;
											goto ip_break;  // 不匹配，返回false
										}
									}
									isIgnoreIp = true; // 匹配，返回true
									break;

								ip_break:
									break;



								}
							}
						}


						//如果strIp不在白名单IP列表中

						if (!isIgnoreIp)
						{
							//将本条日志记录追加到recordFile中保存，方便以后查看可疑记录
							fileRecord << str << '\n';
							hasCtlFile = true;


							ipBegn = ipMap.find(strIp);
							if (ipBegn != ipMap.end())
							{

								switch (i)
								{
								case ssh_sftp_scp_time:
									//只需要存储最多thisFalseTime的时间戳进queue中就行
									if (std::get<ssh_sftp_scp_time>(ipBegn->second).size() == thisFalseTime)
										std::get<ssh_sftp_scp_time>(ipBegn->second).pop();
									std::get<ssh_sftp_scp_time>(ipBegn->second).emplace(ipTime);
									break;
								case threeX_ui_time:
									if (std::get<threeX_ui_time>(ipBegn->second).size() == thisFalseTime)
										std::get<threeX_ui_time>(ipBegn->second).pop();
									std::get<threeX_ui_time>(ipBegn->second).emplace(ipTime);
									break;
								case mysql_time:
									if (std::get<mysql_time>(ipBegn->second).size() == thisFalseTime)
										std::get<mysql_time>(ipBegn->second).pop();
									std::get<mysql_time>(ipBegn->second).emplace(ipTime);
									break;
								case redis_time:
									if (std::get<redis_time>(ipBegn->second).size() == thisFalseTime)
										std::get<redis_time>(ipBegn->second).pop();
									std::get<redis_time>(ipBegn->second).emplace(ipTime);
									break;


								default:
									break;

								}
								std::get<timeString>(ipBegn->second) = ipTime;
							}
							else
							{
								newTuple = defaultTuple;
								std::get<timeString>(newTuple) = ipTime;
								switch (i)
								{
								case ssh_sftp_scp_time:
									std::get<ssh_sftp_scp_time>(newTuple).emplace(ipTime);
									break;
								case threeX_ui_time:
									std::get<threeX_ui_time>(newTuple).emplace(ipTime);
									break;
								case mysql_time:
									std::get<mysql_time>(newTuple).emplace(ipTime);
									break;
								case redis_time:
									std::get<redis_time>(newTuple).emplace(ipTime);
									break;

								default:
									break;

								}
								bit = std::get<super_bit>(newTuple);
								bit.set(ip_type, isStrIPIPv4);
								std::get<super_bit>(newTuple) = static_cast<unsigned char>(bit.to_ulong());
								ipMap.insert(std::make_pair(strIp, newTuple));
							}
						}
					}
					file.close();

					//读取完毕后且文件有内容则清空该文件
					if (!isFileEmpty)
					{
						//检测完每一种类型的文件之后清空存储登录IP的set
						loginIpSet.clear();
						filw.open(everyFile[i], std::ios::trunc | std::ios::binary);
						if (filw)
						{
							filw << "";
							filw.close();
						}
					}
				}
			}
		}

		//如果recordFile有执行过写入，则刷新内存数据到磁盘中
		if (hasCtlFile)
		{
			fileRecord.flush();
			hasCtlFile = false;
		}








		///////////////////////////////////////////////////////////////////////////////////


		//遍历存储IP的map
		if (!ipMap.empty())
		{

			fileBan.seekp(0, std::ios::end);
			beginPos = fileBan.tellp();
			hasCtlFile = false;
			commandPos = commandBuf;
			hasCommand = false;
			banBufBegin = banBufPos = banBuf;
			hasUfwDeny = false;
			conntrackVec.clear();

			//将时间戳转换成字符串保存
			timeBuf[0] = ipTime / 1000000000UL + '0';
			timeBuf[1] = ipTime % 1000000000UL / 100000000UL + '0';
			timeBuf[2] = ipTime % 100000000UL / 10000000UL + '0';
			timeBuf[3] = ipTime % 10000000UL / 1000000UL + '0';
			timeBuf[4] = ipTime % 1000000UL / 100000UL + '0';
			timeBuf[5] = ipTime % 100000UL / 10000UL + '0';
			timeBuf[6] = ipTime % 10000UL / 1000UL + '0';
			timeBuf[7] = ipTime % 1000UL / 100UL + '0';
			timeBuf[8] = ipTime % 100UL / 10UL + '0';
			timeBuf[9] = ipTime % 10UL + '0';


			for (ipBegn = ipMap.begin(); ipBegn != ipMap.end();)
			{
				//取出时间值
				ipTime = std::get<timeString>(ipBegn->second);

				//将当前时间与IP记录时间进行比较,计算出差异时间，单位秒
				diff = currentTime - ipTime;


				//如果尚未执行过封禁操作
				bit = std::get<super_bit>(ipBegn->second);
				if (!bit[has_ban])
				{
					//遍历检查每一项的时间差异，
					//检查每一项是否在各项的findTime内，
					//检查每一项错误次数是否达到各项的falseTime
					//如果有多项达到falseTime,取最大的banTime时间的统计项为封禁类型
					//如果只有一项达到falseTime,该统计项为封禁类型
					isErase = true;
					isMAx = false;
					maxBanTime = 0;


					//遍历检查每一项
					for (i = ssh_sftp_scp_time; i != default_time; ++i)
					{

						//如果本项开启了检查
						if (everyEnableCHeck[i])
						{

							thisFindTime = everyFindTime[i];
							if (!thisFindTime)
								thisFindTime = findTime;

							thisFalseTime = everyFalseTime[i];
							if (!thisFalseTime)
								thisFalseTime = falseTime;

							thisBanTime = everyBanTime[i];
							if (!thisBanTime)
								thisBanTime = banTime;



							switch (i)
							{
							case ssh_sftp_scp_time:
								//遍历std::queue<std::time_t>，将thisFindTime内的时间戳保留下来
								if (std::get<ssh_sftp_scp_time>(ipBegn->second).empty())
									continue;

								//将大于thisFindTime的时间戳剔除掉
								while (!std::get<ssh_sftp_scp_time>(ipBegn->second).empty())
								{
									if (currentTime - std::get<ssh_sftp_scp_time>(ipBegn->second).front() > thisFindTime)
										std::get<ssh_sftp_scp_time>(ipBegn->second).pop();
									else
										break;
								}

								//如果在thisFindTime内的时间戳数量等于thisFalseTime
								if (std::get<ssh_sftp_scp_time>(ipBegn->second).size() == thisFalseTime)
								{
									isMAx = true;
									if (maxBanTime < thisBanTime)
									{
										maxBanTime = thisBanTime;
										//记录下封禁类型，因为解封需要根据封禁类型比较是否到达封禁时间
										std::get<ban_type>(ipBegn->second) = ssh_sftp_scp_time;
										strBanTypeName = "ssh_sftp_scp";
									}
								}
								//如果在thisFindTime内的时间戳数量不为0，则不能进行删除操作
								if (!std::get<ssh_sftp_scp_time>(ipBegn->second).empty())
									isErase = false;

								break;
							case threeX_ui_time:
								//遍历std::queue<std::time_t>，将thisFindTime内的时间戳保留下来
								if (std::get<threeX_ui_time>(ipBegn->second).empty())
									continue;

								//将大于thisFindTime的时间戳剔除掉
								while (!std::get<threeX_ui_time>(ipBegn->second).empty())
								{
									if (currentTime - std::get<threeX_ui_time>(ipBegn->second).front() > thisFindTime)
										std::get<threeX_ui_time>(ipBegn->second).pop();
									else
										break;
								}

								//如果在thisFindTime内的时间戳数量等于thisFalseTime
								if (std::get<threeX_ui_time>(ipBegn->second).size() == thisFalseTime)
								{
									isMAx = true;
									if (maxBanTime < thisBanTime)
									{
										maxBanTime = thisBanTime;
										//记录下封禁类型，因为解封需要根据封禁类型比较是否到达封禁时间
										std::get<ban_type>(ipBegn->second) = threeX_ui_time;
										strBanTypeName = "threeX_ui";
									}
								}
								//如果在thisFindTime内的时间戳数量不为0，则不能进行删除操作
								if (!std::get<threeX_ui_time>(ipBegn->second).empty())
									isErase = false;

								break;

							case mysql_time:
								//遍历std::queue<std::time_t>，将thisFindTime内的时间戳保留下来
								if (std::get<mysql_time>(ipBegn->second).empty())
									continue;

								//将大于thisFindTime的时间戳剔除掉
								while (!std::get<mysql_time>(ipBegn->second).empty())
								{
									if (currentTime - std::get<mysql_time>(ipBegn->second).front() > thisFindTime)
										std::get<mysql_time>(ipBegn->second).pop();
									else
										break;
								}

								//如果在thisFindTime内的时间戳数量等于thisFalseTime
								if (std::get<mysql_time>(ipBegn->second).size() == thisFalseTime)
								{
									isMAx = true;
									if (maxBanTime < thisBanTime)
									{
										maxBanTime = thisBanTime;
										//记录下封禁类型，因为解封需要根据封禁类型比较是否到达封禁时间
										std::get<ban_type>(ipBegn->second) = mysql_time;
										strBanTypeName = "mysql";
									}
								}
								//如果在thisFindTime内的时间戳数量不为0，则不能进行删除操作
								if (!std::get<mysql_time>(ipBegn->second).empty())
									isErase = false;

								break;

							case redis_time:
								//遍历std::queue<std::time_t>，将thisFindTime内的时间戳保留下来
								if (std::get<redis_time>(ipBegn->second).empty())
									continue;

								//将大于thisFindTime的时间戳剔除掉
								while (!std::get<redis_time>(ipBegn->second).empty())
								{
									if (currentTime - std::get<redis_time>(ipBegn->second).front() > thisFindTime)
										std::get<redis_time>(ipBegn->second).pop();
									else
										break;
								}

								//如果在thisFindTime内的时间戳数量等于thisFalseTime
								if (std::get<redis_time>(ipBegn->second).size() == thisFalseTime)
								{
									isMAx = true;
									if (maxBanTime < thisBanTime)
									{
										maxBanTime = thisBanTime;
										//记录下封禁类型，因为解封需要根据封禁类型比较是否到达封禁时间
										std::get<ban_type>(ipBegn->second) = redis_time;
										strBanTypeName = "redis";
									}
								}
								//如果在thisFindTime内的时间戳数量不为0，则不能进行删除操作
								if (!std::get<redis_time>(ipBegn->second).empty())
									isErase = false;

								break;

							default:
								break;
							}
						}

					}

					//判断是否以及达到某一项的最大错误次数
					if (isMAx)
					{
						bit = std::get<super_bit>(ipBegn->second);

						if (std::distance(commandPos, commandBuf + commandBufLen) < 200)
						{
							*commandPos++ = '\0';
							commandPos = commandBuf;
							system(commandBuf);
						}

						switch (thisSystem)
						{
							//ufw 进行封禁操作前需要把允许接入的端口号关闭，插入封禁命令后再重新打开，避免封禁命令插入在后面导致规则失效
						case Ubuntu_system:
							if (!hasUfwDeny)
							{
								std::copy(ufwDisAllow.cbegin(), ufwDisAllow.cend(), commandPos);
								commandPos += ufwDisAllow.size();
								hasUfwDeny = true;
							}
							break;

						}

						//如果是IPV4
						if (bit[ip_type])
						{

							//封禁ip
							switch (thisSystem)
							{
							case Alpine_system:
								std::copy(strIptables_I.cbegin(), strIptables_I.cend(), commandPos);
								commandPos += strIptables_I.size();
								std::copy(ipBegn->first.cbegin(), ipBegn->first.cend(), commandPos);
								commandPos += ipBegn->first.size();
								std::copy(strDrop.cbegin(), strDrop.cend(), commandPos);
								commandPos += strDrop.size();

								break;
							case Ubuntu_system:
								std::copy(ufwDeny.cbegin(), ufwDeny.cend(), commandPos);
								commandPos += ufwDeny.size();
								std::copy(ipBegn->first.cbegin(), ipBegn->first.cend(), commandPos);
								commandPos += ipBegn->first.size();
								//因为string存在map里面，所以这里用string_view存储ip信息即可，节省空间
								conntrackVec.emplace_back(std::string_view(ipBegn->first.c_str(), ipBegn->first.size()));

								break;
							}

							*commandPos++ = ';';
							isIPV4Save = true;

						}
						else    //如果是IPV6
						{
							//封禁ip
							switch (thisSystem)
							{
							case Alpine_system:
								std::copy(strIp6tables_I.cbegin(), strIp6tables_I.cend(), commandPos);
								commandPos += strIp6tables_I.size();
								std::copy(ipBegn->first.cbegin(), ipBegn->first.cend(), commandPos);
								commandPos += ipBegn->first.size();
								std::copy(strDrop.cbegin(), strDrop.cend(), commandPos);
								commandPos += strDrop.size();

								break;
							case Ubuntu_system:
								std::copy(ufwDeny.cbegin(), ufwDeny.cend(), commandPos);
								commandPos += ufwDeny.size();
								std::copy(ipBegn->first.cbegin(), ipBegn->first.cend(), commandPos);
								commandPos += ipBegn->first.size();
								//因为string存在map里面，所以这里用string_view存储ip信息即可，节省空间
								conntrackVec.emplace_back(std::string_view(ipBegn->first.c_str(), ipBegn->first.size()));

								break;
							}

							*commandPos++ = ';';
							isIPV6Save = true;
						}


						//确定执行过iptables操作
						hasCommand = true;
						bit = std::get<super_bit>(ipBegn->second);
						bit.set(has_ban, true);
						std::get<super_bit>(ipBegn->second) = static_cast<unsigned char>(bit.to_ulong());


						//将本次封禁的IP记录保存到文件中，同时将在文件中的位置保存起来
						if (std::distance(banBufBegin, banBuf + banBufLen) < 100)
						{
							fileBan.write(banBuf, std::distance(banBuf, banBufBegin));
							banBufBegin = banBuf;
							hasCtlFile = true;
						}
						banBufPos = banBufBegin;
						std::copy(ipBegn->first.cbegin(), ipBegn->first.cend(), banBufPos);
						banBufPos += ipBegn->first.size();
						*banBufPos++ = space[0];

						//将ipTime转化成字符串写进内存中保存
						std::copy(timeBuf, timeBuf + timeBufLen, banBufPos);
						banBufPos += timeBufLen;

						*banBufPos++ = space[0];
						*banBufPos++ = std::get<ban_type>(ipBegn->second);
						*banBufPos++ = '\n';
						std::get<file_pos>(ipBegn->second) = beginPos;
						beginPos += std::distance(banBufBegin, banBufPos);
						banBufBegin = banBufPos;



						//如果启动了发送email通知功能
						if (enableMail)
						{
							//检查剩余长度是否足够
							if (std::distance(sendPos, sendBuf + sendBufLen) < 100)
							{
								//检测sendBuf到mixSendPos之间的数据是否被改过
								if (!std::equal(curlCheckStr.cbegin(), curlCheckStr.cend(), sendBuf, const_cast<char*>(mixSendPos)))
									std::copy(curlCheckStr.cbegin(), curlCheckStr.cend(), sendBuf);
								std::copy(emailBack.cbegin(), emailBack.cend(), sendPos);
								sendPos += emailBack.size();
								*sendPos++ = '\0';


								//使用curl调用邮件api	
								curlPack.curlPos = 0;
								curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sendBuf);

								//因为发送邮件接口需要进行DNS解析，所以需要开启udp服务
								if (!enableUDP && !hasAllowUDP)
								{
									switch (thisSystem)
									{
									case Alpine_system:
										system(iptablesAllowUDP.c_str());
										break;
									case Ubuntu_system:
										system(ufwAllowUDP.c_str());
										break;
									default:
										break;
									}
									hasAllowUDP = true;
								}

								// 执行请求
								res = curl_easy_perform(curl);

								sendPos = const_cast<char*>(mixSendPos);
							}
							if (!ipBegn->first.empty())
							{
								std::copy(banIP.cbegin(), banIP.cend(), sendPos);
								sendPos += banIP.size();
								std::copy(ipBegn->first.cbegin(), ipBegn->first.cend(), sendPos);
								sendPos += ipBegn->first.size();
								*sendPos++ = ' ';
							}
							if (!strBanTypeName.empty())
							{
								std::copy(banType.cbegin(), banType.cend(), sendPos);
								sendPos += banType.size();
								std::copy(strBanTypeName.cbegin(), strBanTypeName.cend(), sendPos);
								sendPos += strBanTypeName.size();
								*sendPos++ = ' ';
							}
						}
					}

					//判断是否应该将该IP记录数据从ipMap中删除
					if (isErase)
						ipBegn = ipMap.erase(ipBegn);
					else
						++ipBegn;

				}
				else   //已经执行过封禁操作
				{
					//如果当前时间与IP记录时间大于banTime+sleepTime
					//因为封禁操作最迟可能在sleepTime后才进行，所以为了封禁时间达到banTime，
					//需要加上sleepTime来进行判断
					//解除封禁后不对将该IP记录数据是否从ipMap中删除的情况进行判断
					//留到下一次sleepTime时进行检查

					thisBanTime = everyBanTime[std::get<ban_type>(ipBegn->second)];
					if (!thisBanTime)
						thisBanTime = banTime;



					if (diff > thisBanTime + sleepTime)
					{
						//解封ip
						bit = std::get<super_bit>(ipBegn->second);
						//如果是IPV4类型

						if (std::distance(commandPos, commandBuf + commandBufLen) < 100)
						{
							*commandPos++ = '\0';
							commandPos = commandBuf;
							system(commandBuf);
						}
						if (bit[ip_type])
						{
							switch (thisSystem)
							{
							case Alpine_system:
								std::copy(strIptables_D.cbegin(), strIptables_D.cend(), commandPos);
								commandPos += strIptables_D.size();
								std::copy(ipBegn->first.cbegin(), ipBegn->first.cend(), commandPos);
								commandPos += ipBegn->first.size();
								std::copy(strDrop.cbegin(), strDrop.cend(), commandPos);
								commandPos += strDrop.size();

								break;
							case Ubuntu_system:
								std::copy(ufwDeleteDeny.cbegin(), ufwDeleteDeny.cend(), commandPos);
								commandPos += ufwDeleteDeny.size();
								std::copy(ipBegn->first.cbegin(), ipBegn->first.cend(), commandPos);
								commandPos += ipBegn->first.size();

								break;
							}


							*commandPos++ = ';';
							isIPV4Save = true;

						}
						else   //如果是IPV6类型
						{
							switch (thisSystem)
							{
							case Alpine_system:
								std::copy(strIp6tables_D.cbegin(), strIp6tables_D.cend(), commandPos);
								commandPos += strIp6tables_D.size();
								std::copy(ipBegn->first.cbegin(), ipBegn->first.cend(), commandPos);
								commandPos += ipBegn->first.size();
								std::copy(strDrop.cbegin(), strDrop.cend(), commandPos);
								commandPos += strDrop.size();

								break;
							case Ubuntu_system:
								std::copy(ufwDeleteDeny.cbegin(), ufwDeleteDeny.cend(), commandPos);
								commandPos += ufwDeleteDeny.size();
								std::copy(ipBegn->first.cbegin(), ipBegn->first.cend(), commandPos);
								commandPos += ipBegn->first.size();

								break;

							}

							*commandPos++ = ';';
							isIPV6Save = true;

						}



						hasCommand = true;
						bit = std::get<super_bit>(ipBegn->second);
						bit.set(has_ban, false);
						std::get<super_bit>(ipBegn->second) = static_cast<unsigned char>(bit.to_ulong());
						std::get<ban_type>(ipBegn->second) = 0;
						//确定执行过iptables操作

						//将banFile中对应的信息清空，只需要将第一位字符置为' '即可

						fileBan.seekp(std::get<file_pos>(ipBegn->second));
						fileBan.write(space, 1);
						fileBan.seekp(0, std::ios::end);
						hasCtlFile = true;
						hasUnseal = true;
						++unsealNum;

					}

					++ipBegn;
				}
			}
		}

		//检查IP地址记录缓冲区是否有数据需要写入
		if (banBufBegin != banBuf)
		{
			fileBan.write(banBuf, std::distance(banBuf, banBufBegin));
			banBufBegin = banBuf;
			hasCtlFile = true;
		}


		//把写入文件中的数据刷新到文件中
		if (hasCtlFile)
		{
			fileBan.flush();
			hasCtlFile = false;
		}

		//判断是否需要执行system操作
		if (hasCommand)
		{
			*commandPos++ = '\0';
			system(commandBuf);
			hasCommand = false;
		}


		//判断之前有没有进行过iptables操作，有的话保存配置文件并重启iptables服务让规则立即生效
		if (isIPV4Save)
		{
			switch (thisSystem)
			{
			case Alpine_system:
				system(strIptablesSave.c_str());
				system(strIptablesRestart.c_str());
				break;
			case Ubuntu_system:
				if (hasUfwDeny)
				{
					system(ufwAllow.c_str());
					hasUfwDeny = false;
				}
				system(ufwReload.c_str());
				//ufw规则并不会断开已有连接，需要使用conntrack命令断开已有连接
				if (!conntrackVec.empty())
				{
					commandPos = commandBuf;
					for (auto& ipView : conntrackVec)
					{
						if (std::distance(commandPos, commandBuf + commandBufLen) < 100)
						{
							*commandPos++ = '\0';
							commandPos = commandBuf;
							system(commandBuf);
						}
						std::copy(conntrackStr.cbegin(), conntrackStr.cend(), commandPos);
						commandPos += conntrackStr.size();
						std::copy(ipView.cbegin(), ipView.cend(), commandPos);
						commandPos += ipView.size();
						*commandPos++ = ';';
					}
					*commandPos++ = '\0';
					system(commandBuf);
					commandPos = commandBuf;
					conntrackVec.clear();
				}
				break;
			}
			isIPV4Save = false;
		}
		if (isIPV6Save)
		{
			switch (thisSystem)
			{
			case Alpine_system:
				system(strIp6tablesSave.c_str());
				system(strIp6tablesRestart.c_str());
				break;
			case Ubuntu_system:
				if (hasUfwDeny)
				{
					system(ufwAllow.c_str());
					hasUfwDeny = false;
				}
				system(ufwReload.c_str());
				//ufw规则并不会断开已有连接，需要使用conntrack命令断开已有连接
				if (!conntrackVec.empty())
				{
					commandPos = commandBuf;
					for (auto& ipView : conntrackVec)
					{
						if (std::distance(commandPos, commandBuf + commandBufLen) < 100)
						{
							*commandPos++ = '\0';
							commandPos = commandBuf;
							system(commandBuf);
						}
						std::copy(conntrackStr.cbegin(), conntrackStr.cend(), commandPos);
						commandPos += conntrackStr.size();
						std::copy(ipView.cbegin(), ipView.cend(), commandPos);
						commandPos += ipView.size();
						*commandPos++ = ';';
					}
					*commandPos++ = '\0';
					system(commandBuf);
					commandPos = commandBuf;
					conntrackVec.clear();
				}
				break;

			}
			isIPV6Save = false;
		}

		//检查是否需要发送邮件通知
		if (enableMail)
		{
			if (sendPos != mixSendPos)
			{
				if (std::distance(sendPos, sendBuf + sendBufLen) > emailBack.size())
				{
					//检测sendBuf到mixSendPos之间的数据是否被改过
					if (!std::equal(curlCheckStr.cbegin(), curlCheckStr.cend(), sendBuf, const_cast<char*>(mixSendPos)))
						std::copy(curlCheckStr.cbegin(), curlCheckStr.cend(), sendBuf);
					std::copy(emailBack.cbegin(), emailBack.cend(), sendPos);
					sendPos += emailBack.size();
					*sendPos++ = '\0';


					//使用curl调用邮件api	
					curlPack.curlPos = 0;
					curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sendBuf);

					//因为发送邮件接口需要进行DNS解析，所以需要开启udp服务
					if (!enableUDP && !hasAllowUDP)
					{
						switch (thisSystem)
						{
						case Alpine_system:
							system(iptablesAllowUDP.c_str());
							break;
						case Ubuntu_system:
							system(ufwAllowUDP.c_str());
							break;
						default:
							break;
						}
						hasAllowUDP = true;
					}

					// 执行请求
					res = curl_easy_perform(curl);

					//发送邮件后立马关闭udp端口，避免udpFlood
					if (!enableUDP && hasAllowUDP)
					{
						switch (thisSystem)
						{
						case Alpine_system:
							system(iptablesBanUDP.c_str());
							break;
						case Ubuntu_system:
							system(ufwBanUDP.c_str());
							break;
						default:
							break;
						}
						hasAllowUDP = false;
					}


				}
				sendPos = const_cast<char*>(mixSendPos);
			}
		}

		//每24小时执行一次的任务         
		if (++unsealCheckTime == unsealCheckTimeMax)
		{
			//检查是否需要重建banFile以节省硬盘空间
			if (hasUnseal && unsealNum >= maxUnsealNum)
			{
				fileBan.close();
				//从ipMap中重建信息进banFile中
				fileBan.open(banFile, std::ios::out | std::ios::binary);
				if (!fileBan)
					return -100;
				if (!ipMap.empty())
				{
					for (ipBegn = ipMap.begin(); ipBegn != ipMap.end(); ++ipBegn)
					{
						bit = std::get<super_bit>(ipBegn->second);
						if (bit[has_ban])
						{
							beginPos = fileBan.tellp();
							//写入IP地址  时间戳  封禁类型等信息到banFile中
							fileBan << ipBegn->first << ' ' << std::get<timeString>(ipBegn->second) << ' ' << std::get<ban_type>(ipBegn->second) << '\n';
							//将本次IP地址在文件中的位置设置到ipMap中
							std::get<file_pos>(ipBegn->second) = beginPos;
						}
					}
					// 将文件指针移动到文件末尾
					fileBan.flush();
				}
				unsealNum = 0;
				hasUnseal = false;
			}


			//清理message日志
			filw.open(message, std::ios::trunc | std::ios::binary);
			if (filw)
			{
				filw << "";
				filw.close();
			}


			//ssh连接记录日志里面记录了sftp与scp登录记录，
			//所以不再需要进行查阅sftp与scp登录记录 
			//检查sftp与scp连接记录日志
			//每次读取文件前获取当前时间戳，如果时间解析失败则将该时间戳赋值给ipTime
			//读取完毕后清空该文件
			filw.open(sftp, std::ios::trunc | std::ios::binary);
			if (filw)
			{
				filw << "";
				filw.close();
			}


			unsealCheckTime = 0;
		}



		std::this_thread::sleep_for(std::chrono::seconds(sleepTime));
	}



	return 0;
}


